home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
ada
/
gnat1792.zip
/
gnat179b
/
t-adainc
/
a-ngcefu.adb
< prev
next >
Wrap
Text File
|
1994-05-19
|
18KB
|
669 lines
------------------------------------------------------------------------------
-- --
-- GNAT RUNTIME COMPONENTS --
-- --
-- A D A . N U M E R I C S . G C E F --
-- --
-- B o d y --
-- --
-- $Revision: 1.1 $ --
-- --
-- Copyright (c) 1992,1993,1994 NYU, All Rights Reserved --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 2, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING. If not, write --
-- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
-- This is an early trial implementation, simplified for early gnat.
-- It is not a "strict" implementation.
-- All Ada required exception handling is provided.
-- Many special cases are handled locally to avoid unnecessary calls
with Ada.Numerics.Generic_Elementary_Functions;
package body Ada.Numerics.Generic_Complex_Elementary_Functions is
package Elementary_Functions is new
Ada.Numerics.Generic_Elementary_Functions (Real'Base);
use Elementary_Functions;
PI : constant := 3.14159_26535_89793_23846_26433_83279_50288_41971;
PI_2 : constant := PI / 2.0;
Log_Two : constant := 0.69314_71805_59945_30941_72321_21458_17656_80755;
Epsilon : Real'Base;
Square_Root_Epsilon : Real'Base;
Inv_Square_Root_Epsilon : Real'Base;
Root_Root_Epsilon : Real'Base;
Log_Inverse_Epsilon_2 : Real'Base;
Complex_Zero : constant Complex := Compose_From_Cartesian (0.0, 0.0);
Complex_One : constant Complex := Compose_From_Cartesian (1.0, 0.0);
Complex_I : constant Complex := Compose_From_Cartesian (0.0, 1.0);
HALF_PI : constant Complex := Compose_From_Cartesian (PI_2, 0.0);
----------
-- Sqrt --
----------
function Sqrt (X : Complex) return Complex is
Z : Complex := X; -- remove if definition gets fixed
R : Real'Base;
R_X : Real'Base;
R_Y : Real'Base;
XR : Real'Base := abs Re (Z);
YR : Real'Base := abs Im (Z);
A : Real'Base;
begin
if XR > YR then
A := YR / XR;
A := A * A;
if A < 32.0 * Square_Root_Epsilon then
if Re (Z) > 0.0 then
R_X := Sqrt (XR + 0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
R_Y := Sqrt (0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
else
R_X := Sqrt (0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
R_Y := Sqrt (XR + 0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
end if;
else
R := XR * Sqrt (1.0 + A);
R_X := Sqrt (0.5 * (R + Re (Z)));
R_Y := Sqrt (0.5 * (R - Re (Z)));
end if;
else -- YR > XR
A := XR / YR;
A := A * A;
if A < 32.0 * Square_Root_Epsilon then -- YR >> XR
R := YR + 0.5 * XR * XR / YR - 0.125 * (XR * XR / YR) * A;
R_X := Sqrt (0.5 * (YR + (0.5 * XR * XR / YR + Re (Z))));
R_Y := Sqrt (0.5 * (YR + (0.5 * XR * XR / YR - Re (Z))));
else
R := YR * Sqrt (1.0 + A);
R_X := Sqrt (0.5 * (R + Re (Z)));
R_Y := Sqrt (0.5 * (R - Re (Z)));
end if;
end if;
if Im (Z) < 0.0 then -- halve angle, Sqrt of magnitude
R_Y := -R_Y;
end if;
return Compose_From_Cartesian (R_X, R_Y);
exception
when Constraint_Error =>
R := Modulus (Compose_From_Cartesian (Re (Z / 4.0), Im (Z / 4.0)));
R_X := 2.0 * Sqrt (0.5 * R + 0.5 * Re (Z / 4.0));
R_Y := 2.0 * Sqrt (0.5 * R - 0.5 * Re (Z / 4.0));
if Im (Z) < 0.0 then -- halve angle, Sqrt of magnitude
R_Y := -R_Y;
end if;
return Compose_From_Cartesian (R_X, R_Y);
end Sqrt;
---------
-- Log --
---------
function Log (X : Complex) return Complex is
Z : Complex := X;
RE_Z, IM_Z : Real'Base;
begin
if Re (Z) = 0.0 and then Im (Z) = 0.0 then
raise Constraint_Error;
elsif abs (1.0 - Re (Z)) < Root_Root_Epsilon and then
abs Im (Z) < Root_Root_Epsilon then
Set_Re (Z, Re (Z) - 1.0);
return (1.0 - (1.0 / 2.0 -
(1.0 / 3.0 - (1.0 / 4.0) * Z) * Z) * Z) * Z;
end if;
begin
RE_Z := Log (Modulus (Z));
exception
when Constraint_Error =>
RE_Z := Log (Modulus (Z / 2.0)) - Log_Two;
end;
IM_Z := Arctan (Im (Z), Re (Z));
if IM_Z > PI then
IM_Z := IM_Z - 2.0 * PI;
end if;
return Compose_From_Cartesian (RE_Z, IM_Z);
end Log;
---------
-- Exp --
---------
function Exp (X : Complex) return Complex is
Z : Complex := X;
EXP_RE_Z : Real'Base := Exp (Re (Z));
begin
return Compose_From_Cartesian (EXP_RE_Z * Cos (Im (Z)),
EXP_RE_Z * Sin (Im (Z)));
end Exp;
function Exp (X : Imaginary) return Complex is
IM_Z : Real'Base := Im (X);
begin
return Compose_From_Cartesian (Cos (IM_Z), Sin (IM_Z));
end Exp;
--------
-- ** --
--------
function "**"
(Left : Complex;
Right : Complex)
return Complex is
Z1 : Complex := Left;
Z2 : Complex := Right;
begin
if Re (Z2) = 0.0 and then Im (Z2) = 0.0 and then
Re (Z1) = 0.0 and then Im (Z1) = 0.0 then
raise Argument_Error;
elsif Re (Z1) = 0.0 and then Im (Z1) = 0.0 and then
Re (Z2) < 0.0 then
raise Constraint_Error;
elsif Re (Z1) = 0.0 and then Im (Z1) = 0.0 then
return Z1;
elsif Re (Z2) = 0.0 and then Im (Z2) = 0.0 then
return 1.0 + Z2;
elsif Re (Z2) = 1.0 and then Im (Z2) = 0.0 then
return Z1;
else
return Exp (Z2 * Log (Z1));
end if;
end "**";
function "**"
(Left : Real'Base;
Right : Complex)
return Complex is
X : Real'Base := Left;
Z : Complex := Right;
begin
if Re (Z) = 0.0 and then Im (Z) = 0.0 and then
X = 0.0 then
raise Argument_Error;
elsif X = 0.0 and then Re (Z) < 0.0 then
raise Constraint_Error;
elsif X = 0.0 then
return Compose_From_Cartesian (X, 0.0);
elsif Re (Z) = 0.0 and then Im (Z) = 0.0 then
return Complex_One;
elsif Re (Z) = 1.0 and then Im (Z) = 0.0 then
return Compose_From_Cartesian (X, 0.0);
else
return Exp (Log (X) * Z);
end if;
end "**";
function "**" (Left : Complex;
Right : Real'Base) return Complex is
Z : Complex := Left;
Y : Real'Base := Right;
begin
if Y = 0.0 and then
Re (Z) =